using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;

namespace Runtime.DesignPattern
{
    public class GameEventManager : IEventManager
    {
        private readonly Dictionary<string, List<IEventHandler>> _eventHandlers = new();
        private readonly Dictionary<Type, List<IEventHandler>> _genericEventHandlers = new();
        private readonly Dictionary<string, List<Func<IEvent, bool>>> _eventFilters = new();
        private readonly Dictionary<Type, List<Func<IEvent, bool>>> _genericEventFilters = new();
        private readonly Dictionary<IEventHandler, int> _handlerPriorities = new();
        private readonly object _lock = new object();

        public void Subscribe(string eventType, IEventHandler handler)
        {
            if (string.IsNullOrEmpty(eventType))
                throw new ArgumentException("Event type cannot be null or empty", nameof(eventType));

            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            lock (_lock)
            {
                if (!_eventHandlers.ContainsKey(eventType))
                {
                    _eventHandlers[eventType] = new List<IEventHandler>();
                }

                if (!_eventHandlers[eventType].Contains(handler))
                {
                    _eventHandlers[eventType].Add(handler);
                    Debug.Log($"Handler {handler.HandlerId} subscribed to event {eventType}");
                }
            }
        }

        public void Subscribe<TData>(IEventHandler<TData> handler) where TData : struct
        {
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            lock (_lock)
            {
                var eventType = typeof(TData);
                if (!_genericEventHandlers.ContainsKey(eventType))
                {
                    _genericEventHandlers[eventType] = new List<IEventHandler>();
                }

                if (!_genericEventHandlers[eventType].Contains(handler))
                {
                    _genericEventHandlers[eventType].Add(handler);
                    Debug.Log($"Generic handler {handler.HandlerId} subscribed to event type {eventType.Name}");
                }
            }
        }

        public void Unsubscribe(string eventType, IEventHandler handler)
        {
            if (string.IsNullOrEmpty(eventType))
                throw new ArgumentException("Event type cannot be null or empty", nameof(eventType));

            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            lock (_lock)
            {
                if (_eventHandlers.ContainsKey(eventType))
                {
                    if (_eventHandlers[eventType].Remove(handler))
                    {
                        Debug.Log($"Handler {handler.HandlerId} unsubscribed from event {eventType}");
                    }
                }
            }
        }

        public void Unsubscribe<TData>(IEventHandler<TData> handler) where TData : struct
        {
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            lock (_lock)
            {
                var eventType = typeof(TData);
                if (_genericEventHandlers.ContainsKey(eventType))
                {
                    if (_genericEventHandlers[eventType].Remove(handler))
                    {
                        Debug.Log($"Generic handler {handler.HandlerId} unsubscribed from event type {eventType.Name}");
                    }
                }
            }
        }

        public async Task PublishAsync(IEvent @event)
        {
            if (@event == null)
                throw new ArgumentNullException(nameof(@event));

            Debug.Log($"Publishing event: {@event}");

            if (!ShouldPublishEvent(@event))
            {
                Debug.Log($"Event {@event.EventType} was filtered out");
                return;
            }

            await PublishToHandlers(@event);
        }

        public Task PublishAsync(string eventType, object eventData, string sourceId, string targetId = null)
        {
            throw new NotImplementedException();
        }

        public Task PublishAsync<TData>(IEvent<TData> @event) where TData : struct
        {
            throw new NotImplementedException();
        }

        public Task PublishAsync<TData>(string eventType, TData eventData, string sourceId, string targetId = null) where TData : struct
        {
            throw new NotImplementedException();
        }

        // public Task PublishAsync(string eventType, object eventData, string sourceId, string targetId = null)
        // {
        //     var @event = new GameEvent(eventType, eventData, sourceId, targetId);
        //     return PublishAsync(@event);
        // }

        // public async Task PublishAsync<TData>(IEvent<TData> @event) where TData : struct
        // {
        //     if (@event == null)
        //         throw new ArgumentNullException(nameof(@event));
        //
        //     Debug.Log($"Publishing generic event: {@event}");
        //
        //     if (!ShouldPublishEvent(@event))
        //     {
        //         Debug.Log($"Generic event {@event.EventType} was filtered out");
        //         return;
        //     }
        //
        //     await PublishToHandlers(@event);
        // }

        // public Task PublishAsync<TData>(string eventType, TData eventData, string sourceId, string targetId = null) where TData : struct
        // {
        //     var @event = new GameEvent<TData>(eventType, eventData, sourceId, targetId);
        //     return PublishAsync(@event);
        // }

        public void ClearAllSubscriptions()
        {
            lock (_lock)
            {
                _eventHandlers.Clear();
                _genericEventHandlers.Clear();
                Debug.Log("All event subscriptions cleared");
            }
        }

        public bool HasSubscribers(string eventType)
        {
            if (string.IsNullOrEmpty(eventType))
                throw new ArgumentException("Event type cannot be null or empty", nameof(eventType));

            lock (_lock)
            {
                return _eventHandlers.ContainsKey(eventType) && _eventHandlers[eventType].Any();
            }
        }

        public bool HasSubscribers<TData>() where TData : struct
        {
            lock (_lock)
            {
                var eventType = typeof(TData);
                return _genericEventHandlers.ContainsKey(eventType) && _genericEventHandlers[eventType].Any();
            }
        }

        public void AddEventFilter(string eventType, Func<IEvent, bool> filter)
        {
            if (string.IsNullOrEmpty(eventType))
                throw new ArgumentException("Event type cannot be null or empty", nameof(eventType));

            if (filter == null)
                throw new ArgumentNullException(nameof(filter));

            lock (_lock)
            {
                if (!_eventFilters.ContainsKey(eventType))
                {
                    _eventFilters[eventType] = new List<Func<IEvent, bool>>();
                }
                _eventFilters[eventType].Add(filter);
                Debug.Log($"Added filter for event {eventType}");
            }
        }

        public void AddEventFilter<TData>(Func<IEvent<TData>, bool> filter) where TData : struct
        {
            if (filter == null)
                throw new ArgumentNullException(nameof(filter));

            lock (_lock)
            {
                var eventType = typeof(TData);
                if (!_genericEventFilters.ContainsKey(eventType))
                {
                    _genericEventFilters[eventType] = new List<Func<IEvent, bool>>();
                }
                _genericEventFilters[eventType].Add(evt => filter((IEvent<TData>)evt));
                Debug.Log($"Added generic filter for event type {eventType.Name}");
            }
        }

        public void RemoveEventFilter(string eventType, Func<IEvent, bool> filter)
        {
            if (string.IsNullOrEmpty(eventType))
                throw new ArgumentException("Event type cannot be null or empty", nameof(eventType));

            if (filter == null)
                throw new ArgumentNullException(nameof(filter));

            lock (_lock)
            {
                if (_eventFilters.ContainsKey(eventType))
                {
                    _eventFilters[eventType].Remove(filter);
                    Debug.Log($"Removed filter for event {eventType}");
                }
            }
        }

        public void RemoveEventFilter<TData>(Func<IEvent<TData>, bool> filter) where TData : struct
        {
            if (filter == null)
                throw new ArgumentNullException(nameof(filter));

            lock (_lock)
            {
                var eventType = typeof(TData);
                if (_genericEventFilters.ContainsKey(eventType))
                {
                    _genericEventFilters[eventType].Remove(evt => filter((IEvent<TData>)evt));
                    Debug.Log($"Removed generic filter for event type {eventType.Name}");
                }
            }
        }

        public void SetHandlerPriority(IEventHandler handler, int priority)
        {
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            lock (_lock)
            {
                _handlerPriorities[handler] = priority;
                Debug.Log($"Set priority {priority} for handler {handler.HandlerId}");
            }
        }

        public int GetHandlerPriority(IEventHandler handler)
        {
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            lock (_lock)
            {
                return _handlerPriorities.TryGetValue(handler, out int priority) ? priority : 0;
            }
        }

        private bool ShouldPublishEvent(IEvent @event)
        {
            lock (_lock)
            {
                if (_eventFilters.ContainsKey(@event.EventType))
                {
                    return _eventFilters[@event.EventType].All(filter => filter(@event));
                }

                var eventType = @event.GetType();
                if (_genericEventFilters.ContainsKey(eventType))
                {
                    return _genericEventFilters[eventType].All(filter => filter(@event));
                }

                return true;
            }
        }

        private async Task PublishToHandlers(IEvent @event)
        {
            List<IEventHandler> handlers;
            lock (_lock)
            {
                handlers = new List<IEventHandler>();

                // 获取普通事件处理器
                if (_eventHandlers.ContainsKey(@event.EventType))
                {
                    handlers.AddRange(_eventHandlers[@event.EventType]);
                }

                // 获取泛型事件处理器
                var eventType = @event.GetType();
                if (_genericEventHandlers.ContainsKey(eventType))
                {
                    handlers.AddRange(_genericEventHandlers[eventType]);
                }
            }

            // 按优先级排序处理器
            var sortedHandlers = handlers.OrderByDescending(h => GetHandlerPriority(h));

            foreach (var handler in sortedHandlers)
            {
                try
                {
                    if (handler.CanHandle(@event))
                    {
                        await handler.HandleEventAsync(@event);
                    }
                }
                catch (Exception ex)
                {
                    Debug.LogError($"Error handling event {@event.EventType} by handler {handler.HandlerId}: {ex}");
                }
            }
        }
    }
}